package persistent.prestige.console.netty.dubbo.server;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import persistent.prestige.console.netty.dubbo.net.Request;
import persistent.prestige.console.netty.dubbo.net.Response;
import persistent.prestige.console.netty.dubbo.server.bs.ServiceExecutor;
import persistent.prestige.console.netty.dubbo.utils.LogUtils;

/**
 * 业务转发handler
 * @author dingwei2
 *
 */
public class DispatchHandler extends ChannelHandlerAdapter {
	
	/**
	 * 业务线程池
	 * 
	 */
	private static ExecutorService businessThreadPools = Executors.newFixedThreadPool(10);

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// TODO Auto-generated method stub
		Request request = (Request)msg;
		
		if(request.getRequestType() == 1 ) { //服务调用
			//这里会有线程切换
			businessThreadPools.submit(new Task(request, ctx));
		} else { //心跳包
			//如果是心跳包，直接在IO线程中执行
			//在这里，返回OK
			LogUtils.log("服务器准备响应请求ID:" + request.getRequestId() + "心跳包");
			ctx.write( new Response(request.getRequestId(), (short)0, "Ok"));
		}
		
		
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		// TODO Auto-generated method stub
		super.exceptionCaught(ctx, cause);
	}
	
	private static class Task implements Runnable {
		
		private Request request;
		private ChannelHandlerContext ctx;
		
		public Task(Request request, ChannelHandlerContext ctx) {
			this.request = request;
			this.ctx = ctx;
		}

		public void run() {
			// TODO Auto-generated method stub
			
			/**
			 * 这里的哲学 在业务线程中调用 ChannelHanlerContext 的 write方法，
			 * netty会检测当前运行的线程是否在Channel所绑定的线程模型中，如果不在，会立即返回，并将任务提交给
			 * 与Channel绑定的线程池，故与通道的读、写等操作，都会在Channel绑定的线程池中执行，也就是通常说的IO线程。
			 * 如果在在业务线程中执行write方法，会发送一次线程切换，故dubbo提供了多种转发策略，例如心跳包，等没有必要在业务线程池
			 * 中执行，而是直接在IO线程中执行的原因所在。
			 */ 
			ctx.writeAndFlush(ServiceExecutor.executor(request));
		}
		
	}

	

}
